home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / nrcmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-10  |  26.1 KB  |  1,165 lines

  1. /* net/rom user command processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <ctype.h>
  8. #include <time.h>
  9. #include <string.h>
  10. #include "global.h"
  11. #include "config.h"
  12. #ifdef NETROM
  13. #include "mbuf.h"
  14. #include "ax25.h"
  15. #include "mailbox.h"
  16. #include "netrom.h"
  17. #include "nr4.h"
  18. #include "timer.h"
  19. #include "iface.h"
  20. #include "cmdparse.h"
  21. #include "session.h"
  22. #include "socket.h"
  23. #include "commands.h"
  24. #include "files.h"
  25.  
  26. /* Nodes message broadcast address: "NODES" in shifted ASCII */
  27. /* defined in ax25rout.c: Ax25multi[1] */
  28.  
  29. char Nr4user[AXALEN];
  30.  
  31. char *Nr4states[] = {
  32.     "Disconnected",
  33.     "Conn Pending",
  34.     "Connected",
  35.     "Disc Pending",
  36.     "Listen"
  37. } ;
  38.  
  39. char *Nr4reasons[] = {
  40.     "Normal",
  41.     "By Peer",
  42.     "Timeout",
  43.     "Reset",
  44.     "Refused"
  45. } ;
  46.  
  47. int Nr_save = 1;     /* NET/ROM Route Save on by default */
  48. int donrsave __ARGS((void));
  49.  
  50. static char *Nodelist = NULLCHAR;
  51. static struct timer Nodetimer ;    /* timer for nodes broadcasts */
  52. static struct timer Obsotimer ;    /* timer for aging routes */
  53. static char badcall[] = "Bad destination callsign\n";
  54. static char badnb[] = "Bad neighbor callsign\n";
  55.  
  56. int
  57. doroutedump(argc,argv,p)
  58. int argc;
  59. char *argv[];
  60. void *p;
  61. {
  62. #define MAX_LES_ROUTES    150
  63.  
  64.     struct nrroute_tab *rp ;
  65.     char buf[18], temp[18], les_routes[MAX_LES_ROUTES][18], *cp;
  66.     int count = 0, column = 1, in, out, i;
  67.  
  68.     for (i = 0 ; i < NRNUMCHAINS ; i++) {
  69.         for (rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  70.             if(count > MAX_LES_ROUTES - 1)
  71.                 break;
  72.             strcpy(buf,rp->alias) ;
  73.             /* remove trailing spaces */
  74.             if ((cp = strchr(buf,' ')) == NULLCHAR)
  75.                 cp = &buf[strlen(buf)] ;
  76.             if (cp != buf)          /* don't include colon for null alias */
  77.                 *cp++ = ':' ;
  78.             pax25(cp,rp->call) ;
  79.             if(argc == 9) {
  80.                 count++;
  81.                 strcpy(les_routes[count],buf);
  82.                 continue;
  83.             }
  84.             if(strstr(buf,"TCP") != NULL
  85.               || strstr(buf,"NOS") != NULL
  86.               || strstr(buf,"IP") != NULL) {
  87.                 count++;
  88.                 strcpy(les_routes[count],buf);
  89.             }
  90.         }
  91.         if(count > MAX_LES_ROUTES - 1) {
  92.             tprintf("\nOnly %d routes displayed\n",MAX_LES_ROUTES);
  93.             break;
  94.         }
  95.     }
  96.     for (out = 1; out < count; out++)
  97.         for (in = out+1; in < count+1; in++)
  98.             if (strcmp(les_routes[out],les_routes[in]) > 0 ) {
  99.                 strcpy(temp, les_routes[in]);
  100.                 strcpy(les_routes[in], les_routes[out]);
  101.                 strcpy(les_routes[out], temp);
  102.             }
  103.  
  104.     for(i = 1; i <= count; i++) {
  105.         tprintf("%-16s  ", les_routes[i]);
  106.         if( column++ == 4) {
  107.             tputc('\n');
  108.             column = 1;
  109.         }
  110.     }
  111.     if(column != 1)
  112.         tputc('\n');
  113.     return 0 ;
  114. }
  115.  
  116. /* print detailed information on an individual route */
  117. int
  118. dorouteinfo(argc,argv,p)
  119. int argc ;
  120. char *argv[] ;
  121. void *p;
  122. {
  123.     struct nrroute_tab *rp ;
  124.     struct nr_bind *bp ;
  125.     struct nrnbr_tab *np ;
  126.     char dest[AXALEN], neighbor[AXBUF], alias[AXBUF], *cp;
  127.  
  128.     if (setcall(dest,argv[1]) == -1) {
  129.         tputs (badcall);
  130.         return -1 ;
  131.     }
  132.  
  133.     if(putalias(alias,argv[1],0) != -1
  134.       && (cp = find_nralias(alias)) != NULLCHAR)
  135.         memcpy(dest,cp,AXALEN);
  136.  
  137.     if((rp = find_nrroute(dest)) == NULLNRRTAB) {
  138.         if(argc < 9)
  139.             tprintf("*** no route to %s\n",pax25(neighbor,dest)) ;
  140.         return -1 ;
  141.     }
  142.  
  143.     for (bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next) {
  144.         np = bp->via ;
  145.         if(tprintf("%1s %3d  %3d  %-8s  %s\n",
  146.          (bp->flags & NRB_PERMANENT ? "P" :
  147.          bp->flags & NRB_RECORDED ? "R" : " "),
  148.          bp->quality,bp->obsocnt,
  149.          Nrifaces[np->iface].iface->name,
  150.          pax25(neighbor,np->call)) == EOF)
  151.             break;
  152.     }
  153.     return 0 ;
  154. }
  155.  
  156. /* convert a null-terminated alias name to a blank-filled, upcased */
  157. /* version.  Return -1 on failure. */
  158. int
  159. putalias(to,from,complain)
  160. char *to, *from ;
  161. int complain ;
  162. {
  163.     int len, i ;
  164.  
  165.     if ((len = strlen(from)) > ALEN) {
  166.         if (complain)
  167.             tputs ("Max six chars\n") ;
  168.         return -1 ;
  169.     }
  170.  
  171.     for (i = 0 ; i < ALEN ; i++) {
  172.         if (i < len) {
  173.             if (islower(*from))
  174.                 *to++ = toupper(*from++) ;
  175.             else
  176.                 *to++ = *from++ ;
  177.         }
  178.         else
  179.             *to++ = ' ' ;
  180.     }
  181.  
  182.     *to = '\0' ;
  183.     return 0 ;
  184. }
  185.  
  186. /* find a netrom interface, gives a msg if 'msg' is set != 0 */
  187. static int near
  188. nrif_lookup(call,msg)
  189. char *call;
  190. int msg;
  191. {
  192.     int i;
  193.  
  194.     for (i = 0 ; i < Nr_numiface ; i++)
  195.         if (!strcmp(Nrifaces[i].iface->name,call))
  196.             break ;
  197.     if (i == Nr_numiface) {
  198.         if(msg)
  199.             tprintf(Badif,call);
  200.         return -1 ;
  201.     }
  202.     return i;
  203. }
  204.  
  205. /* Add a route */
  206. static int
  207. dorouteadd(argc, argv,p)
  208. int argc ;
  209. char *argv[] ;
  210. void *p;
  211. {
  212.     char alias[AXALEN], dest[AXALEN], neighbor[AXALEN];
  213.     unsigned quality ;
  214.     int i ;
  215.  
  216.     /* format alias (putalias prints error message if necessary) */
  217.     if (putalias(alias,argv[1],1) == -1)
  218.         return -1 ;
  219.  
  220.     /* format destination callsign */
  221.     if (setcall(dest,argv[2]) == -1) {
  222.         tputs(badcall);
  223.         return -1 ;
  224.     }
  225.  
  226.     if((i = nrif_lookup(argv[3],1)) == -1)
  227.         return -1;
  228.  
  229.     /* format neighbor address string */
  230.     if (setcall(neighbor,argv[5]) == -1) {
  231.         tputs(badcall);
  232.         return -1;
  233.     }
  234. #ifdef XXX
  235.     /* Change from 871225 -- no digis in net/rom table */
  236.     if (argc > 6)
  237.         tputs("digis given: set route with ax25 route cmd\n");
  238. #endif
  239.     /* get and check quality value */
  240.     quality = (unsigned)min(atoi(argv[4]),255);
  241.  
  242.     return nr_routeadd(alias,dest,i,quality,neighbor,1,0) ;
  243. }
  244.  
  245.  
  246. /* drop a route */
  247. static int
  248. doroutedrop(argc,argv,p)
  249. int argc ;
  250. char *argv[] ;
  251. void *p;
  252. {
  253.     char dest[AXALEN], neighbor[AXALEN] ;
  254.     int i ;
  255.  
  256.     /* format destination and neighbor callsigns */
  257.     if (setcall(dest,argv[1]) == -1) {
  258.         tputs(badcall);
  259.         return -1 ;
  260.     }
  261.     if (setcall(neighbor,argv[2]) == -1) {
  262.         tputs(badnb);
  263.         return -1 ;
  264.     }
  265.  
  266.     if((i = nrif_lookup(argv[3],1)) == -1)
  267.         return -1;
  268.  
  269.     return nr_routedrop(dest,neighbor,i) ;
  270. }
  271.  
  272. /* make an interface available to net/rom */
  273. static int
  274. dointerface(argc,argv,p)
  275. int argc ;
  276. char *argv[] ;
  277. void *p;
  278. {
  279.     int i ;
  280.     struct iface *ifp ;
  281.  
  282.     if (Nr_iface == NULLIF)
  283.         nr_attach(0,0,p);
  284.  
  285.     if (Nr_numiface >= NRNUMIFACE) {
  286.         tprintf("Max %d NET/ROM ifaces\n",NRNUMIFACE);
  287.         return 1 ;
  288.     }
  289.     if((ifp = if_lookup(argv[1])) == NULLIF){
  290.         tprintf(Badif,argv[1]);
  291.         return 1;
  292.     }
  293.     for (i = 0 ; i < Nr_numiface ; i++)
  294.         if (Nrifaces[i].iface == ifp) {
  295.             tprintf("Iface %s already registered\n",argv[1]) ;
  296.             return 1 ;
  297.         }
  298.  
  299.     Nrifaces[Nr_numiface].iface = ifp ;
  300.  
  301.     if (putalias(Nrifaces[Nr_numiface].alias,argv[2],1) == -1)
  302.         return 1 ;
  303.  
  304.     Nrifaces[Nr_numiface].quality = (unsigned)min(atoi(argv[3]),255);
  305.     Nr_numiface++ ;                    /* accept this interface */
  306.     return 0 ;
  307. }
  308.  
  309. static void
  310. donodetick()
  311. {
  312.     if(Nr_numiface) {
  313.         int i;
  314.  
  315.         stop_timer(&Nodetimer);
  316.  
  317.         for (i = 0 ; i < Nr_numiface ; i++)
  318.             nr_bcnodes(i,Ax25multi[1]) ;
  319.  
  320.         if(strchr(Nodelist,'*') != NULLCHAR) {
  321.             char *cp1 = strxdup(Nodelist);
  322.             char *cp = strtok(cp1,"*");
  323.  
  324.             while((cp = strtok(NULL,"*")) != NULLCHAR)
  325.                 nr_bcnodes(Nr_numiface - 1,cp);
  326.  
  327.             xfree(cp1);
  328.         }
  329.     }
  330.     /* restart timer */
  331.     start_timer(&Nodetimer);
  332. }
  333.  
  334. /* Broadcast nodes list on named interface. */
  335. static int
  336. dobcnodes(argc,argv,p)
  337. int argc ;
  338. char *argv[] ;
  339. void *p;
  340. {
  341.     int j;
  342.     char call[AXALEN];
  343.  
  344.     int i = nrif_lookup(argv[1],(argc < 3) ? 1 : 0);
  345.  
  346.     if(argc < 3) {
  347.         if(i == -1)
  348.             return -1;
  349.         nr_bcnodes(i,Ax25multi[1]);
  350.         return 0;
  351.     }
  352.     if(i == -1) {
  353.         argc++;
  354.         argv--;
  355.     }
  356.     if(Nodelist) {
  357.         xfree(Nodelist);
  358.         Nodelist = NULLCHAR;
  359.     }
  360.     Nodelist = cxallocw(argc,AXBUF);
  361.  
  362.     for(j = 1; j < argc; j++) {
  363.         if(setcall(call,argv[j]) == -1)
  364.             continue;
  365.         strcat(Nodelist,call);
  366.         strcat(Nodelist,"*");
  367.     }
  368.     donodetick();
  369.     return 0;
  370. }
  371.  
  372. /* Set outbound node broadcast interval */
  373. static int
  374. donodetimer(argc,argv,p)
  375. int argc;
  376. char *argv[];
  377. void *p;
  378. {
  379.     if(argc < 2){
  380.         tprintf("Nodetimer %lu/%lu s\n",
  381.             read_timer(&Nodetimer)/1000L,
  382.             dur_timer(&Nodetimer)/1000L);
  383.         return 0;
  384.     }
  385.     /* in case it's already running */
  386.     stop_timer(&Nodetimer) ;
  387.     /* what to call on timeout */
  388.     Nodetimer.func = (void (*) __ARGS((void *))) donodetick;
  389.     Nodetimer.arg = NULLCHAR;                        /* dummy value */
  390.     set_timer(&Nodetimer,atol(argv[1]) * 1000L);    /* set timer duration */
  391.     start_timer(&Nodetimer);                        /* and fire it up */
  392.     return 0;
  393. }
  394.  
  395. /* Go through the routing table, reducing the obsolescence count of
  396.  * non-permanent routes, and purging them if the count reaches 0
  397.  */
  398. static void
  399. doobsotick()
  400. {
  401.     struct nrnbr_tab *np ;
  402.     struct nrroute_tab *rp, *rpnext ;
  403.     struct nr_bind *bp, *bpnext ;
  404.     int i ;
  405.  
  406.     stop_timer(&Obsotimer);
  407.  
  408.     for (i = 0 ; i < NRNUMCHAINS ; i++) {
  409.         for (rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rpnext) {
  410.             rpnext = rp->next ;     /* save in case we free this route */
  411.             for (bp = rp->routes ; bp != NULLNRBIND ; bp = bpnext) {
  412.                 bpnext = bp->next ;    /* in case we free this binding */
  413.                 if (bp->flags & NRB_PERMANENT)    /* don't age these */
  414.                     continue ;
  415.                 if (--bp->obsocnt == 0) {        /* time's up! */
  416.                     if (bp->next != NULLNRBIND)
  417.                         bp->next->prev = bp->prev ;
  418.                     if (bp->prev != NULLNRBIND)
  419.                         bp->prev->next = bp->next ;
  420.                     else
  421.                         rp->routes = bp->next ;
  422.                     rp->num_routes-- ;            /* one less binding */
  423.                     np = bp->via ;                /* find the neighbor */
  424.                     xfree((char *)bp) ;                /* now we can free the bind */
  425.                     /* Check to see if we can free the neighbor */
  426.                     if (--np->refcnt == 0) {
  427.                         if (np->next != NULLNTAB)
  428.                             np->next->prev = np->prev ;
  429.                         if (np->prev != NULLNTAB)
  430.                             np->prev->next = np->next ;
  431.                         else {
  432.                             Nrnbr_tab[nrhash(np->call)] = np->next ;
  433.                         }
  434.                         xfree((char *)np) ;    /* free the storage */
  435.                     }
  436.                 }
  437.             }
  438.             if (rp->num_routes == 0) {        /* did we free them all? */
  439.                 if (rp->next != NULLNRRTAB)
  440.                     rp->next->prev = rp->prev ;
  441.                 if (rp->prev != NULLNRRTAB)
  442.                     rp->prev->next = rp->next ;
  443.                 else
  444.                     Nrroute_tab[i] = rp->next ;
  445.  
  446.                 xfree((char *)rp) ;
  447.             }
  448.         }
  449.     }
  450.     start_timer(&Obsotimer) ;
  451. }
  452.  
  453. /* Set timer for aging routes */
  454. static int
  455. doobsotimer(argc,argv,p)
  456. int argc;
  457. char *argv[];
  458. void *p;
  459. {
  460.     if(argc < 2){
  461.         tprintf("Obsotimer %lu/%lu s\n",
  462.             read_timer(&Obsotimer)/1000L,
  463.             dur_timer(&Obsotimer)/1000L);
  464.         return 0;
  465.     }
  466.     /* just in case it's already running */
  467.     stop_timer(&Obsotimer) ;
  468.     /* what to call on timeout */
  469.     Obsotimer.func = (void (*) __ARGS((void *))) doobsotick;
  470.     Obsotimer.arg = NULLCHAR;                        /* dummy value */
  471.     set_timer(&Obsotimer,atol(argv[1]) * 1000L);    /* set timer duration */
  472.     start_timer(&Obsotimer);                        /* and fire it up */
  473.     return 0;
  474. }
  475.  
  476. /* display a list of <callsign,interface> pairs from the filter
  477.  * list.
  478.  */
  479. static int
  480. donfdump()
  481. {
  482.     int i, column = 1 ;
  483.     struct nrnf_tab *fp ;
  484.     char buf[16] ;
  485.  
  486.     for (i = 0 ; i < NRNUMCHAINS ; i++)
  487.         for (fp = Nrnf_tab[i] ; fp != NULLNRNFTAB ; fp = fp->next) {
  488.             pax25(buf,fp->neighbor) ;
  489.             tprintf("%-7s  %-8s  %-3d   ",
  490.              buf,Nrifaces[fp->iface].iface->name, fp->quality) ;
  491.             if (column++ == 3) {
  492.                 if(tputs("\n") == EOF)
  493.                     return 0;
  494.                 column = 1 ;
  495.             }
  496.         }
  497.  
  498.     if (column != 1)
  499.         tputs("\n") ;
  500.  
  501.     return 0 ;
  502. }
  503.  
  504. /* add an entry to the filter table */
  505. static int
  506. donfadd(argc,argv,p)
  507. int argc ;
  508. char *argv[] ;
  509. void *p;
  510. {
  511.     char neighbor[AXALEN] ;
  512.     int i ;
  513.     unsigned qual = (argc >= 4) ? atoi(argv[3]) : Nrifaces[i].quality;
  514.  
  515.     /* format callsign */
  516.     if (setcall(neighbor,argv[1]) == -1) {
  517.         tputs(badnb);
  518.         return -1 ;
  519.     }
  520.  
  521.     if((i = nrif_lookup(argv[2],1)) == -1)
  522.         return -1;
  523.  
  524.     return nr_nfadd(neighbor,i,qual) ;
  525. }
  526.  
  527. /* drop an entry from the filter table */
  528. static int
  529. donfdrop(argc,argv,p)
  530. int argc ;
  531. char *argv[] ;
  532. void *p;
  533. {
  534.     char neighbor[AXALEN] ;
  535.     int i ;
  536.  
  537.     /* format neighbor callsign */
  538.     if (setcall(neighbor,argv[1]) == -1) {
  539.         tputs(badnb);
  540.         return -1 ;
  541.     }
  542.  
  543.     if((i = nrif_lookup(argv[2],1)) == -1)
  544.         return -1;
  545.  
  546.     return nr_nfdrop(neighbor,i) ;
  547. }
  548.  
  549. /* nodefilter mode subcommand */
  550. static int
  551. donfmode(argc,argv,p)
  552. int argc ;
  553. char *argv[] ;
  554. void *p;
  555. {
  556.     if (argc < 2) {
  557.         tputs("Filter mode: ");
  558.         switch (Nr_nfmode) {
  559.         case NRNF_NOFILTER:
  560.             tputs("none\n") ;
  561.             break ;
  562.         case NRNF_ACCEPT:
  563.             tputs("accept\n") ;
  564.             break ;
  565.         case NRNF_REJECT:
  566.             tputs("reject\n") ;
  567.             break ;
  568.         default:
  569.             tputs("unknown\n") ;
  570.         }
  571.     } else {
  572.         switch (tolower(argv[1][0])) {
  573.         case 'n':
  574.             Nr_nfmode = NRNF_NOFILTER ;
  575.             break ;
  576.         case 'a':
  577.             Nr_nfmode = NRNF_ACCEPT ;
  578.             break ;
  579.         case 'r':
  580.             Nr_nfmode = NRNF_REJECT ;
  581.             break ;
  582.         default:
  583.             tputs("Usage: mode <accept|reject|none>\n");
  584.             return -1 ;
  585.         }
  586.     }
  587.     return 0;
  588. }
  589.  
  590. /* nodefilter command multiplexer */
  591. static int
  592. donodefilter(argc,argv,p)
  593. int argc ;
  594. char *argv[] ;
  595. void *p;
  596. {
  597.     struct cmds Nfcmds[] = {
  598.         "add",    donfadd,    0, 3,
  599.             "netrom nodefilter add <neighbor> <iface> [<quality>]",
  600.         "drop",    donfdrop,    0, 3,
  601.             "netrom nodefilter drop <neighbor> <iface>",
  602.         "mode",    donfmode,    0, 0,    NULLCHAR,
  603.         NULLCHAR,
  604.     } ;
  605.  
  606.     if (argc < 2) {
  607.         donfdump() ;
  608.         return 0 ;
  609.     }
  610.     return subcmd(Nfcmds,argc,argv,p) ;
  611. }
  612.  
  613. /* netrom network packet time-to-live initializer */
  614. static int
  615. donrttl(argc, argv,p)
  616. int argc ;
  617. char *argv[] ;
  618. void *p;
  619. {
  620.     return setshort(&Nr_ttl,"TTL",argc,argv);
  621. }
  622.  
  623. /* verbose route broadcast */
  624. static int
  625. donrverbose(argc,argv,p)
  626. int argc ;
  627. char *argv[] ;
  628. void *p;
  629. {
  630.     return setbool(&Nr_verbose,"Verbose",argc,argv);
  631. }
  632.  
  633. /* allow automatic derating of netrom routes on link failure */
  634. static int
  635. donrderate(argc,argv,p)
  636. int argc ;
  637. char *argv[] ;
  638. void *p;
  639. {
  640.     extern int Nr_derate;
  641.  
  642.     return setbool(&Nr_derate,"Derate",argc,argv);
  643. }
  644.  
  645. /* promiscuous acceptance of broadcasts */
  646. static int
  647. donrpromisc(argc,argv,p)
  648. int argc ;
  649. char *argv[] ;
  650. void *p;
  651. {
  652.     extern int Nr_promisc;
  653.  
  654.     return setbool(&Nr_promisc,"Promiscuous",argc,argv);
  655. }
  656.  
  657. /* Initiate a NET/ROM transport connection */
  658. static int
  659. donrconnect(argc,argv,p)
  660. int argc ;
  661. char *argv[] ;
  662. void *p;
  663. {
  664.     char *np ;
  665.     struct sockaddr_nr lsocket, fsocket;
  666.     char alias[AXBUF];
  667.     struct session *sp;
  668.  
  669.     /* Get a session descriptor */
  670.     if ((sp = newsession(argv[1],NRSESSION,1,1)) == NULLSESSION) {
  671.         tputs(Nosess);
  672.         return 1;
  673.     }
  674.  
  675.     if((sp->s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
  676.         tputs(Nosocket);
  677.         goto quit;
  678.     }
  679.     lsocket.nr_family = AF_NETROM;
  680.     /* Set up our local username, bind would use Mycall instead */
  681.     memcpy(lsocket.nr_addr.user,Nr4user,AXALEN);
  682.     /* Putting anything else than Mycall here will not work */
  683.     memcpy(lsocket.nr_addr.node,Mycall,AXALEN);
  684.     bind(sp->s,(char *)&lsocket,sizeof(struct sockaddr_nr));
  685.  
  686.     /* See if the requested destination could be an alias, and */
  687.     /* find and use it if it is.  Otherwise assume it is an ax.25 */
  688.     /* address. */
  689.  
  690.     if (putalias(alias,argv[1],0) != -1 &&
  691.         (np = find_nralias(alias)) != NULLCHAR) {
  692.         memcpy(fsocket.nr_addr.user,np,AXALEN) ;
  693.         memcpy(fsocket.nr_addr.node,np,AXALEN) ;
  694.     } else {    /* parse ax25 callsign */
  695.         /* Only the user callsign of the remote station is never used by */
  696.         /* NET/ROM, but it is needed for the psocket() call. */
  697.         setcall(fsocket.nr_addr.user,argv[1]);
  698.         setcall(fsocket.nr_addr.node,argv[1]);
  699.     }
  700.     fsocket.nr_family = AF_NETROM;
  701.     pax25(alias,fsocket.nr_addr.node);
  702.     if(!(tel_connect(sp, (char *)&fsocket, sizeof(struct sockaddr_nr))))
  703.         return 0;
  704. quit:
  705.     keywait(NULLCHAR,1);
  706.     freesession(sp);
  707.     return 1;
  708. }
  709.  
  710. /* Reset a net/rom connection abruptly */
  711. static int
  712. donrreset(argc,argv,p)
  713. int argc;
  714. char *argv[];
  715. void *p;
  716. {
  717.     struct nr4cb *cb = (struct nr4cb *)htol(argv[1]);
  718.  
  719.     if(!nr4valcb(cb)){
  720.         tputs(Notval);
  721.         return 1;
  722.     }
  723.     reset_nr4(cb);
  724.     return 0;
  725. }
  726.  
  727. /* Allows a manual forced close on a net/rom connection */
  728. static int
  729. donrclose(int argc,char *argv[],void *p)
  730. {
  731.     struct nr4cb *cb = (struct nr4cb *)htol(argv[1]);
  732.  
  733.     if(!nr4valcb(cb)) {
  734.         tputs(Notval);
  735.         return 1;
  736.     }
  737.     disc_nr4(cb);
  738.     return 0;
  739. }
  740.  
  741. /* Force retransmission on a net/rom connection */
  742. static int
  743. donrkick(argc,argv,p)
  744. int argc;
  745. char *argv[];
  746. void *p;
  747. {
  748.     struct nr4cb *cb = (struct nr4cb *)htol(argv[1]);
  749.  
  750.     if(!nr4valcb(cb)){
  751.         tputs(Notval);
  752.         return 1;
  753.     }
  754.     return kick_nr4(cb);
  755. }
  756.  
  757. /* netrom transport ACK delay timer */
  758. static int
  759. donracktime(argc, argv,p)
  760. int argc ;
  761. char *argv[] ;
  762. void *p;
  763. {
  764.     return setintrc(&Nr4acktime,"Ack delay",argc,argv,1,60);
  765. }
  766.  
  767. /* netrom transport choke timeout */
  768. static int
  769. donrchoketime(argc, argv,p)
  770. int argc ;
  771. char *argv[] ;
  772. void *p;
  773. {
  774.     return setintrc(&Nr4choketime,"Choke timeout",argc,argv,10,3600);
  775. }
  776.  
  777. /* netrom transport initial round trip time */
  778.  
  779. static int
  780. donrirtt(argc, argv,p)
  781. int argc ;
  782. char *argv[] ;
  783. void *p;
  784. {
  785.     return setintrc(&Nr4irtt,"IRTT",argc,argv,5,360);
  786. }
  787.  
  788. /* netrom transport receive queue length limit.  This is the */
  789. /* threshhold at which we will CHOKE the sender. */
  790.  
  791. static int
  792. donrqlimit(argc, argv,p)
  793. int argc ;
  794. char *argv[] ;
  795. void *p;
  796. {
  797.     return setintrc(&Nr4qlimit,"Queue limit",argc,argv,1,4096);
  798. }
  799.  
  800. /* Display or change our NET/ROM username */
  801. static int
  802. donruser(argc,argv,p)
  803. int argc;
  804. char *argv[];
  805. void *p;
  806. {
  807.     char buf[AXBUF];
  808.  
  809.     if(argc < 2){
  810.         tprintf("%s\n",pax25(buf,Nr4user));
  811.         return 0;
  812.     }
  813.     if(setcall(Nr4user,argv[1]) == -1)
  814.         return -1;
  815.     Nr4user[ALEN] |= E;
  816.     return 0;
  817. }
  818.  
  819. /* netrom transport maximum window.  This is the largest send and */
  820. /* receive window we may negotiate */
  821.  
  822. static int
  823. donrwindow(argc, argv,p)
  824. int argc ;
  825. char *argv[] ;
  826. void *p;
  827. {
  828.     return setintrc(&Nr4window,"Window",argc,argv,1,NR4MAXWIN);
  829. }
  830.  
  831. /* netrom transport maximum retries.  This is used in connect and */
  832. /* disconnect attempts; I haven't decided what to do about actual */
  833. /* data retries yet. */
  834.  
  835. static int
  836. donrretries(argc, argv,p)
  837. int argc ;
  838. char *argv[] ;
  839. void *p;
  840. {
  841.     return setshort(&Nr4retries,"Retry limit",argc,argv);
  842. }
  843.  
  844. /* Display the status of NET/ROM connections */
  845.  
  846. static int
  847. donrstatus(argc, argv,p)
  848. int argc ;
  849. char *argv[] ;
  850. void *p;
  851. {
  852.     int i ;
  853.     struct nr4cb *cb ;
  854.     char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
  855.  
  856.     if (argc < 2) {
  857.         tputs("     &CB Snd-W Snd-Q Rcv-Q     LUser      RUser @Node     State\n");
  858.         for (i = 0 ; i < NR4MAXCIRC ; i++) {
  859.             if ((cb = Nr4circuits[i].ccb) == NULLNR4CB)
  860.                 continue ;
  861.             pax25(luser,cb->local.user) ;
  862.             pax25(ruser,cb->remote.user) ;
  863.             pax25(node,cb->remote.node) ;
  864.             if(tprintf("%8lx   %3d %5d %5d %9s  %9s %-9s %s\n",
  865.              ptol(cb), cb->nbuffered, len_q(cb->txq),
  866.              len_p(cb->rxq), luser, ruser, node,
  867.              Nr4states[cb->state]) == EOF)
  868.                 break;
  869.         }
  870.         return 0 ;
  871.     }
  872.  
  873.     cb = (struct nr4cb *)htol(argv[1]) ;
  874.     if (!nr4valcb(cb)) {
  875.         tputs(Notval) ;
  876.         return 1 ;
  877.     }
  878.  
  879.     donrdump(cb) ;
  880.     return 0 ;
  881. }
  882.  
  883. /* Dump one control block */
  884.  
  885. void
  886. donrdump(cb)
  887. struct nr4cb *cb ;
  888. {
  889.     char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
  890.     unsigned seq ;
  891.     struct nr4txbuf *b ;
  892.     struct timer *t ;
  893.  
  894.     pax25(luser,cb->local.user) ;
  895.     pax25(ruser,cb->remote.user) ;
  896.     pax25(node,cb->remote.node) ;
  897.  
  898.     tprintf("Local: %s %d/%d Remote: %s @ %s %d/%d State: %s\n",
  899.            luser, cb->mynum, cb->myid, ruser, node,
  900.            cb->yournum, cb->yourid, Nr4states[cb->state]) ;
  901.  
  902.     tprintf("Window: %-5u Rxpect: %-5u RxNext: %-5u RxQ: %-5d %s\n",
  903.            cb->window, uchar(cb->rxpected), uchar(cb->rxpastwin),
  904.            len_p(cb->rxq), cb->qfull ? "RxCHOKED" : "") ;
  905.  
  906.     tprintf(" Unack: %-5u Txpect: %-5u TxNext: %-5u TxQ: %-5d %s\nTACK: ",
  907.            cb->nbuffered, uchar(cb->ackxpected), uchar(cb->nextosend),
  908.            len_q(cb->txq), cb->choked ? "TxCHOKED" : "") ;
  909.  
  910.     if (run_timer(&cb->tack))
  911.         tprintf("%lu", read_timer(&cb->tack)) ;
  912.     else
  913.         tputs("-") ;
  914.     tprintf("/%lu ms  TChoke: ", dur_timer(&cb->tack)) ;
  915.  
  916.     if (run_timer(&cb->tchoke))
  917.         tprintf("%lu", read_timer(&cb->tchoke)) ;
  918.     else
  919.         tputs("-") ;
  920.     tprintf("/%lu ms  TCD: ", dur_timer(&cb->tchoke)) ;
  921.  
  922.     if (run_timer(&cb->tcd))
  923.         tprintf("%lu", read_timer(&cb->tcd)) ;
  924.     else
  925.         tputs("-") ;
  926.  
  927.     tprintf("/%lu ms\nTries: %u  Inactive: %ld/%ld sec",
  928.         dur_timer(&cb->tcd),
  929.         cb->cdtries,
  930.         read_timer(&cb->inactivity)/1000L,
  931.         dur_timer(&cb->inactivity)/1000L);
  932.  
  933.     if(cb->blevel)
  934.         tprintf("  Backoff Level %u",cb->blevel);
  935.  
  936.     tprintf("\nSRTT %ld ms Mean dev %ld ms\n", cb->srtt, cb->mdev) ;
  937.  
  938.     /* If we are connected and the send window is open, display */
  939.     /* the status of all the buffers and their timers */
  940.     if (cb->state == NR4STCON && cb->nextosend != cb->ackxpected) {
  941.         tputs("TxBuffers:  Seq  Size  Tries  Timer\n") ;
  942.  
  943.         for (seq = cb->ackxpected ;
  944.              nr4between(cb->ackxpected, seq, cb->nextosend) ;
  945.              seq = (seq + 1) & NR4SEQMASK) {
  946.  
  947.             b = &cb->txbufs[seq % cb->window] ;
  948.             t = &b->tretry ;
  949.  
  950.             if(tprintf("            %3u   %3d  %5d  %lu/%lu\n",
  951.               seq, len_p(b->data), b->retries + 1, read_timer(t), dur_timer(t))
  952.               == EOF)
  953.                 break;
  954.         }
  955.     }
  956. }
  957.  
  958. static int
  959. dominquality(argc,argv,p)
  960. int argc ;
  961. char *argv[] ;
  962. void *p ;
  963. {
  964.     return setintrc(&(int16)Nr_autofloor,"MinQual",argc,argv,1,255);
  965. }
  966.  
  967. /* Switch on/off saving of netrom routes to disk */
  968. static int
  969. doroutesave(argc,argv,p)
  970. int argc ;
  971. char *argv[] ;
  972. void *p;
  973. {
  974.     return setbool(&Nr_save,"NET/ROM Route Save",argc,argv);
  975. }
  976.  
  977. static char * near
  978. getarg(char *line)
  979. {
  980.   char  *arg;
  981.   int  c;
  982.   static char  *p;
  983.  
  984.   if (line) p = line;
  985.   while (isspace(uchar(*p))) p++;
  986.   arg = p;
  987.   while (*p && !isspace(uchar(*p))) {
  988.     c = (uchar(*p));
  989.     *p++ = c;
  990.   }
  991.   if (*p) *p++ = '\0';
  992.   return arg;
  993. }
  994. /*
  995.  * Load saved NET/ROM routes - called at startup
  996.  */
  997. int
  998. donrload(void)
  999. {
  1000.         FILE *fn;
  1001.         int quality, i, j;
  1002.         char buff[80], *alias = 0, *dest, *type, *iface, *neighbor;
  1003.         char ax25_alias[AXALEN], ax25_dest[AXALEN], ax25_nbor[AXALEN], *ptr;
  1004.  
  1005.         if((fn = open_file(Nrroutefile,READ_TEXT,0,1)) == NULLFILE)
  1006.                 return 1;
  1007.  
  1008.         while(fgets(buff,80,fn) != NULL) {
  1009.                 alias = dest = type = iface = neighbor = 0;
  1010.                 quality = 0;
  1011.                 if((ptr = strchr(buff,':')) == 0){
  1012.                         *alias = '\0';
  1013.                         dest = getarg(buff);
  1014.                 } else {
  1015.                         *ptr = ' ';
  1016.                         alias = getarg(buff);
  1017.                         dest = getarg(0);
  1018.                 }
  1019.                 type = getarg(0);
  1020.                 quality = atoi(getarg(0));
  1021.                 getarg(0);
  1022.                 iface = getarg(0);
  1023.                 neighbor = getarg(0);
  1024.  
  1025.                 /* find interface */
  1026.                 for(i = 0 ; i < Nr_numiface ; i++)
  1027.                         if(!strcmp(Nrifaces[i].iface->name,iface))
  1028.                                 break ;
  1029.  
  1030.                 if(i == Nr_numiface) {
  1031.                         tprintf(Badif,iface);
  1032.                         continue;
  1033.                 }
  1034.  
  1035.                 /* Convert to NET/ROM routing table formats */
  1036.                 putalias(ax25_alias, alias, 0);
  1037.                 setcall(ax25_dest, dest);
  1038.                 setcall(ax25_nbor, neighbor);
  1039.  
  1040.                 /* get and check quality value */
  1041.                 if(quality  > 255)
  1042.                         quality = 255;
  1043.  
  1044.                 if (strcmp(type,"P") == 0)
  1045.                         j = 0;
  1046.                 else
  1047.                         j = 1;
  1048.  
  1049.                 nr_routeadd(ax25_alias,ax25_dest,i,quality,ax25_nbor,!j,j);
  1050.         }
  1051.         fclose(fn);
  1052.         return 0;
  1053. }
  1054. /*
  1055.  * Save NET/ROM routes in file for reading when we start up again.
  1056.  * This function is called at each tick of the netrom obsotimer.
  1057.  *
  1058.  */
  1059.  
  1060. int
  1061. donrsave(void)
  1062. {
  1063.     struct nrroute_tab *rp ;
  1064.     struct nr_bind *bp ;
  1065.     struct nrnbr_tab *np ;
  1066.     char neighbor[AXBUF], buf[18], *cp;
  1067.     int i;
  1068.     FILE *fn;
  1069.  
  1070. #ifdef __TURBOC__
  1071.     if((fn = open_file(Nrroutefile,"wt+",0,1)) == NULLFILE)
  1072. #else
  1073.     if((fn = open_file(Nrroutefile,"w+",0,1)) == NULLFILE)
  1074. #endif
  1075.         return 1;
  1076.  
  1077.     for(i = 0 ; i < NRNUMCHAINS ; i++){
  1078.         for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next){
  1079.             sprintf(buf,"%.*s",AXALEN,rp->alias) ;
  1080.             /* remove trailing spaces */
  1081.             if((cp = strchr(buf,' ')) == NULLCHAR)
  1082.                 cp = &buf[strlen(buf)] ;
  1083.             if(cp != buf)        /* don't include colon for null alias */
  1084.                 *cp++ = ':' ;
  1085.             for(bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
  1086.                 pax25(cp,rp->call) ;
  1087.                 fprintf(fn,"%-16s  ",buf) ;
  1088.                 np = bp->via ;
  1089.                 fprintf(fn,"%1s %3d  %3d  %-8s  %s\n",
  1090.                   (bp->flags & NRB_PERMANENT ? "P" :
  1091.                   bp->flags & NRB_RECORDED ? "R" : "X"),
  1092.                   bp->quality,bp->obsocnt,
  1093.                   Nrifaces[np->iface].iface->name,
  1094.                   pax25(neighbor,np->call));
  1095.             }
  1096.         }
  1097.     }
  1098.     fclose(fn);
  1099.     return 0;
  1100. }
  1101.  
  1102. /* Route command multiplexer */
  1103. static int
  1104. donrroute(argc, argv,p)
  1105. int argc ;
  1106. char *argv[] ;
  1107. void *p;
  1108. {
  1109.     struct cmds Routecmds[] = {
  1110.         "add",    dorouteadd,        0, 6,
  1111.             "netrom route add <alias> <destination> <iface> <quality> <neighbor>",
  1112.         "drop",    doroutedrop,     0, 4,
  1113.             "netrom route drop <destination> <neighbor> <iface>",
  1114.         "info", dorouteinfo,     0, 2,
  1115.             "netrom route info <destination>",
  1116.         "save", doroutesave,    0, 0,
  1117.             "netrom route save [<0|1>]",
  1118.         NULLCHAR,
  1119.     } ;
  1120.  
  1121.     if (argc < 2) {
  1122.         return doroutedump(9,0,p) ;
  1123.     }
  1124.     return subcmd(Routecmds,argc,argv,p) ;
  1125. }
  1126.  
  1127. /* Command multiplexer */
  1128. int
  1129. donetrom(argc,argv,p)
  1130. int argc ;
  1131. char *argv[] ;
  1132. void *p;
  1133. {
  1134.     struct cmds Nrcmds[] = {
  1135.     "acktime",        donracktime,    0, 0,    NULLCHAR,
  1136.     "bcnodes",        dobcnodes,        0, 2,    "netrom bcnodes <iface> [<call>]",
  1137.     "connect",        donrconnect, 1024, 2,    "netrom connect <node>",
  1138.     "choketime",    donrchoketime,    0, 0,    NULLCHAR,
  1139.     "close",        donrclose,        0, 2,    "netrom close <nrcb>",
  1140.     "derate",        donrderate,        0, 0,    NULLCHAR,
  1141.     "interface",    dointerface,    0, 4,
  1142.         "netrom interface <iface> <alias> <quality>",
  1143.     "irtt",            donrirtt,        0, 0,    NULLCHAR,
  1144.     "kick",            donrkick,        0, 2,    "netrom kick <nrcb>",
  1145.     "minquality",    dominquality,    0, 0,    NULLCHAR,
  1146.     "nodefilter",    donodefilter,    0, 0,    NULLCHAR,
  1147.     "nodetimer",    donodetimer,    0, 0,    NULLCHAR,
  1148.     "obsotimer",    doobsotimer,    0, 0,    NULLCHAR,
  1149.     "promiscuous",    donrpromisc,    0, 0,    NULLCHAR,
  1150.     "qlimit",        donrqlimit,        0, 0,    NULLCHAR,
  1151.     "reset",        donrreset,        0, 2,    "netrom reset <nrcb>",
  1152.     "retries",        donrretries,    0, 0,    NULLCHAR,
  1153.     "route",        donrroute,        0, 0,    NULLCHAR,
  1154.     "status",        donrstatus,        0, 0,    NULLCHAR,
  1155.     "ttl",            donrttl,        0, 0,    NULLCHAR,
  1156.     "user",            donruser,        0, 0,    NULLCHAR,
  1157.     "verbose",        donrverbose,    0, 0,    NULLCHAR,
  1158.     "window",        donrwindow,        0, 0,    NULLCHAR,
  1159.     NULLCHAR,
  1160.     } ;
  1161.     return subcmd(Nrcmds,argc,argv,p) ;
  1162. }
  1163.  
  1164. #endif /* NETROM */
  1165.